<html>
<head>
<title>Constraints and Statistics</title>
<script>
var mystream;
var pc1;
var pc2;

$ = function(id) {
  return document.getElementById(id);
}

function log(txt) {
  console.log(txt);
}

function openCamera() {
  if (mystream) {
    mystream.stop();
  }
  navigator.webkitGetUserMedia(cameraConstraints(), gotStream, function() {
     log("GetUserMedia failed");
    });
} 

function gotStream(stream) {
  log("GetUserMedia succeeded");
  mystream = stream;
  $("local-video").src = webkitURL.createObjectURL(stream);
}

function cameraConstraints() {
  var constraints = {};
  constraints.audio = true;
  constraints.video = { mandatory: {}, optional: [] };
  if ($("minwidth").value != "0") {
    constraints.video.mandatory.minWidth = $("minwidth").value;
  }
  if ($("maxwidth").value != "0") {
    constraints.video.mandatory.maxWidth = $("maxwidth").value;
  }
  if ($("minheight").value != "0") {
    constraints.video.mandatory.minHeight = $("minheight").value;
  }
  if ($("maxheight").value != "0") {
    constraints.video.mandatory.maxHeight = $("maxheight").value;
  }
  if ($("frameRate").value != "0") {
    constraints.video.mandatory.minFrameRate = $("frameRate").value;
  }
  log('Camera constraints are ' + JSON.stringify(constraints));
  $("cameraConstraints").innerHTML = JSON.stringify(constraints, null, ' ');
  return constraints;
}

function streamConstraints() {
  var constraints = { mandatory: {}, optional: [] };
  if ($("bandwidth").value != "0") {
    constraints.optional[0] = { 'bandwidth' : $('bandwidth').value };
  }
  log('Constraints are ' + JSON.stringify(constraints));
  $("addStreamConstraints").innerHTML = JSON.stringify(constraints, null, ' ');
  return constraints;
}



function connect() {
  pc1 = new webkitRTCPeerConnection(null);
  pc2 = new webkitRTCPeerConnection(null);
  pc1.addStream(mystream, streamConstraints());
  log('PC1 creating offer');
  pc1.onnegotiationeeded = function() {
    log('Negotiation needed - PC1');
  }
  pc2.onnegotiationeeded = function() {
    log('Negotiation needed - PC2');
  }
  pc1.onicecandidate = function(e) {
    log('Candidate PC1');
    if (e.candidate) {
      pc2.addIceCandidate(new RTCIceCandidate(e.candidate));
    }
  }
  pc2.onicecandidate = function(e) {
    log('Candidate PC2');
    if (e.candidate) {
      pc1.addIceCandidate(new RTCIceCandidate(e.candidate));
    }
  }
  pc2.onaddstream = function(e) {
    log('PC2 got stream');
    $('remote-video').src = webkitURL.createObjectURL(e.stream);
    log('Remote video is ' + $('remote-video').src);
  }
  pc1.createOffer(function(desc) {
    log('PC1 offering');
    pc1.setLocalDescription(desc);
    pc2.setRemoteDescription(desc);
    pc2.createAnswer(function(desc2) {
      log('PC2 answering');
      pc2.setLocalDescription(desc2);
      pc1.setRemoteDescription(desc2);
    });
  });
}

// Display statistics
var statCollector = setInterval(function() {
  var display = function(str) {
    $('bitrate').innerHTML = str;
  }

  display("No stream");
  if (pc2 && pc2.remoteStreams[0]) {
    if (pc2.getStats) {
      display('No stats callback');
      pc2.getStats(function(stats) {
        log('Raw stats ' + stats);
        var statsString = '';
        var results = stats.result();
        log('Raw results ' + results);
        for (var i = 0; i < results.length; ++i) {
          var res = results[i];
          log(i + ': ' + JSON.stringify(res));
          statsString += '<h3>Report ';
          statsString += i;
          statsString += '</h3>';
          if (res.local) {
            statsString += "<p>Local ";
            statsString += dumpStats(res.local);
          }
          if (res.remote) {
            statsString += "<p>Remote ";
            statsString += dumpStats(res.remote);
          }
        }
        $('stats').innerHTML = statsString;
        display('No bitrate stats');
      });
    } else {
      display('No stats function. Use at least Chrome 24.0.1285');
    }
  } else {
    log('Not connected yet');
  }
  // Collect some stats from the video tags.
  local_video = $('local-video');
  if (local_video) {
     $('local-video-stats').innerHTML = local_video.videoWidth +
         'x' + local_video.videoHeight;
  }
  remote_video = $('remote-video');
  if (remote_video) {
     $('remote-video-stats').innerHTML = remote_video.videoWidth +
         'x' + remote_video.videoHeight;
  }
}, 1000);

// Dumping a stats variable as a string.
// might be named toString?
function dumpStats(obj) {
  var statsString = 'Timestamp:';
  statsString += obj.timestamp;
  if (obj.names) {
    log('Have names function');
    names = obj.names();
    for (var i = 0; i < names.length; ++i) {
       statsString += '<br>';
       statsString += names[i];
       statsString += ':';
       statsString += obj.stat(names[i]);
    }
  } else {
    log('No names function');
    if (obj.stat('audioOutputLevel')) {
      statsString += "audioOutputLevel: ";
      statsString += obj.stat('audioOutputLevel');
      statsString += "<br>";
    }
  }
  return statsString;
}
  

// Utility to show the value of a field in a span called name+Display
function showValue(name, value) {
  $(name + 'Display').innerHTML = value;
}
</script>
</head>
<body>
<h1>Constraints and Statistics</h1>
This page is meant to give some hints on how one can use constraints and statistics in WebRTC applications.
<p>
The form to the left gives constraints you can set on the getUserMedia call.
When you hit "open", it will (re)open the camera with these constraints.
<p>
The left picture is the local preview. The right picture is the picture
after being passed through the PeerConnection (locally).
<p>
Underneath the picture you will see a running display of how many Kbits/sec
the video feed uses for transmission.
<hr>
<table>
<tr>
<td align="top">
<h2>getUserMedia constraints</h2>
<table>
<tr><td><td>Min<td>Max
<tr><td>Horizontal
<td><input type="range" id="minwidth" min="0" max="1280" value="300"
  onchange="showValue(this.id, this.value)">
<td><input type="range" id="maxwidth" min="0" max="1280" value="640"
  onchange="showValue(this.id, this.value)">
<td><span id="minwidthDisplay">300</span>-<span id="maxwidthDisplay">640</span>
<tr><td>Vertical
<td><input type="range" id="minheight" min="0" max="1280" value="200"
  onchange="showValue(this.id, this.value)">
<td><input type="range" id="maxheight" min="0" max="1280" value="480"
  onchange="showValue(this.id, this.value)">
<td><span id="minheightDisplay">200</span>-<span id="maxheightDisplay">480</span>
<tr><td>
FrameRate
<td colspan=2><input type="range" id="frameRate" min="0" max="60" value="30"
  onchange="showValue(this.id, this.value)">
<td><span id="frameRateDisplay">30</span>
</table>
<input type="submit" name="capture" value="Capture!" onclick="openCamera()">
</td>
<td align="top">
<h2>addStream constraints</h2>
Maximum bitrate
<input type="range" id="bandwidth" min="0" max="2000" value="1000"
  onchange="showValue(this.id, this.value)">
<span id="bandwidthDisplay">1000</span>
<br>
<input type="submit" name="connect" value="Connect!" onclick="connect()">
</td>
</tr>
<tr>
<td>
<video id="local-video" autoplay width=400></video>
</td>
<td>
<video id="remote-video" autoplay width=400></video>
</td>
<tr>
<td><span id="local-video-stats"></span>
<td><span id="remote-video-stats"></span>
<br>
<span id="bitrate">Bitrate unknown</span>
</td>
</tr>
<tr>
<td><pre><span id="cameraConstraints"></span></pre>
<td><pre><span id="addStreamConstraints"></span></pre>
</table>
<h2>Statistics report display</h2>
<div id="stats">Stats will appear here.</div>
</body>
</html>
